/*
 * common_bytequeue.h
 *
 *  Created on: 2011-5-7
 *      Author: chenl
 */

#ifndef COMMON_BYTEQUEUE_H_
#define COMMON_BYTEQUEUE_H_

#include "common/common_queue.h"
#include "common/common_err.h"
#include "common/common_util.h"
#include <assert.h>
#include <string.h>

typedef struct _BuffParam
{
	uint8_t* 	pBuff;
	uint32_t 	len;
}BuffParam;

//non-thread-safe
template<unsigned CAPACITY>
class CByteQueue : public IQueue<BuffParam>
{
public:
	CByteQueue()
	: size_(0), head_(0), tail_(0), pBuff_(0)
	{}
	~CByteQueue()
	{}

public:
	virtual int32_t Initialize()
	{
		pBuff_ = new uint8_t[CAPACITY];
//		memset(pBuff_, 0, sizeof(pBuff_));
		return S_OK;
	}
	virtual int32_t Uninitialize()
	{
		delete [] pBuff_;
		return S_OK;
	}

public:
	virtual int32_t Push(const BuffParam& buff)
	{
		if (unlikely(NULL == buff.pBuff))
		{
			return E_NULLPOINTER;
		}

		if (unlikely(0 == buff.len))
		{
			return S_OK;
		}

		//隊列已滿
		if (IsFull())
		{
			return E_QUEUEISFULL;
		}
		//隊列已損壞
		if (unlikely(head_ >= CAPACITY || tail_ >= CAPACITY ))
		{
			head_ = tail_ = size_ = 0;
			return E_QUEUEISCLOBBERED;
		}

		unsigned tail = GetTail();
		unsigned capacity = Capacity();
		unsigned size = Size();
		unsigned dataLen = buff.len + sizeof(buff.len);

		//是否可以完整拷貝
		if (dataLen + size > capacity)
		{
			return E_QUEUEISFULL;
		}

		//先拷貝 后修改隊列參數
		//儅有綫程競爭時，如果隊列參數已經更改，則保證拷貝已經完成

		//將數據包長度壓入隊列
		uint8_t* pLen = (uint8_t*)&buff.len;
		for (unsigned i = 0; i < sizeof(buff.len) / sizeof(*buff.pBuff); ++i)
		{
			memcpy(pBuff_ + tail, &pLen[i], 1);
			tail = (tail + 1) % CAPACITY;
		}

		if (tail + buff.len < capacity)
		{
			memcpy(pBuff_ + tail, buff.pBuff, buff.len);
			tail += buff.len;
		}
		else
		{
			memcpy(pBuff_ + tail, buff.pBuff, capacity - tail);
			memcpy(pBuff_, buff.pBuff +  capacity - tail, buff.len - (capacity - tail));
			tail = (tail + buff.len) % capacity;
		}
		size_ += dataLen;
		SetTail(tail);

		return S_OK;
	}

	//buff.len為輸入輸出參數
	//輸入: buff最大長度
	//輸出: buff實際長度
	virtual int32_t Pop(BuffParam& buff)
	{
		if (unlikely(NULL == buff.pBuff))
		{
			buff.len = 0;
			return E_NULLPOINTER;
		}
		//隊列空
		if (this->IsEmpty())
		{
			buff.len = 0;
			return E_QUEUEISEMPTY;
		}

		if (unlikely(0 >= buff.len))
		{
			buff.len = 0;
			return E_INVALIDARG;
		}

		int head = GetHead();
		unsigned capacity = Capacity();
		uint32_t len = 0;

		//隊列已損壞
		if (unlikely(head_ >= CAPACITY || tail_ >= CAPACITY))
		{
			buff.len = 0;
			head_ = tail_ = size_ = 0;
			return E_QUEUEISCLOBBERED;
		}

		//先拷貝 后修改隊列參數
		//儅有綫程競爭時，如果隊列參數已經更改，則保證拷貝已經完成

		//獲取數據包長度
		uint8_t* pLen = (uint8_t*)&len;
		for (unsigned i = 0; i < sizeof(buff.len)/ sizeof(*buff.pBuff); ++i)
		{
			memcpy(&pLen[i], pBuff_ + head, 1);
			head = (head + 1) % capacity;
		}
		assert( 0 != len);
		if (unlikely(0 == len))
		{
			buff.len = 0;
			head_ = tail_ = size_ = 0;
			return E_QUEUEISCLOBBERED;
		}
		if (len > buff.len)
		{
			buff.len = 0;
			return E_INVALIDARG;
		}

		//拷貝數據
		if (head + (int)len < (int)capacity)
		{
			memcpy(buff.pBuff, pBuff_ + head, len);
			head += len;
		}
		else
		{
			memcpy(buff.pBuff, pBuff_ + head, capacity - head);
			memcpy(buff.pBuff +  capacity - head, pBuff_, len - (capacity - head));
			head = (head + len) % capacity;
		}
		size_ -= len + sizeof(buff.len);
		SetHead(head);
		buff.len = len;

		return S_OK;
	}


	virtual int32_t Front(BuffParam& buff) const
	{
		if (unlikely(NULL == buff.pBuff))
		{
			buff.len = 0;
			return E_NULLPOINTER;
		}
		//隊列空
		if (this->IsEmpty())
		{
			buff.len = 0;
			return E_QUEUEISEMPTY;
		}

		if (unlikely(0 >= buff.len))
		{
			buff.len = 0;
			return E_INVALIDARG;
		}

		int head = GetHead();
		unsigned capacity = Capacity();
		uint32_t len = 0;

		//隊列已損壞
		if (unlikely(head_ >= CAPACITY || tail_ >= CAPACITY))
		{
			buff.len = 0;
			return E_QUEUEISCLOBBERED;
		}

		//先拷貝 后修改隊列參數
		//儅有綫程競爭時，如果隊列參數已經更改，則保證拷貝已經完成

		//獲取數據包長度
		uint8_t* pLen = (uint8_t*)&len;
		for (unsigned i = 0; i < sizeof(buff.len)/ sizeof(*buff.pBuff); ++i)
		{
			memcpy(&pLen[i], pBuff_ + head, 1);
			head = (head + 1) % capacity;
		}
		assert( 0 != len);
		if (unlikely(0 == len))
		{
			buff.len = 0;
			return E_QUEUEISCLOBBERED;
		}
		if (len > buff.len)
		{
			buff.len = 0;
			return E_INVALIDARG;
		}

		//拷貝數據
		if (head + (int)len < (int)capacity)
		{
			memcpy(buff.pBuff, pBuff_ + head, len);
			head += len;
		}
		else
		{
			memcpy(buff.pBuff, pBuff_ + head, capacity - head);
			memcpy(buff.pBuff +  capacity - head, pBuff_, len - (capacity - head));
			head = (head + len) % capacity;
		}
		return S_OK;
	}

	virtual void Clear()
	{
		head_ = tail_ = size_ = 0;
	}

	virtual bool IsFull() const
	{
		return CAPACITY == size_;
	}
	virtual bool IsEmpty() const
	{
		return 0 == size_;
	}
	virtual unsigned Size() const
	{
		return size_;
	}
	virtual unsigned Capacity() const
	{
		return CAPACITY;
	}

protected:
	unsigned GetHead() const
	{
		return head_;
	}
	unsigned GetTail() const
	{
		return tail_;
	}
	void SetHead(int head)
	{
		head_ = head;
	}
	void SetTail(int tail)
	{
		tail_ = tail;
	}

private:
	//流式數據無法從尾部解析長度
	virtual int32_t Back(BuffParam& buff) const
	{
		return S_FALSE;
	}

private:
	unsigned 	size_;
	unsigned	head_;
	unsigned	tail_;
	uint8_t*	pBuff_;	//stream buff
};

#endif /* COMMON_BYTEQUEUE_H_ */
